#include "TcpServer.hpp"
#include "Socket.hpp"
#include "InetAddr.hpp"
#include "protocol.hpp"
#include "Calculate.hpp"

const std::string ip = "127.0.0.1";

using exec_t = std::function<std::shared_ptr<Response>(std::shared_ptr<Request>)>;

enum
{
    USAGEERROR = 1
};

class Service
{
public:
    Service(exec_t exec)
        : _exec(exec)
    {
    }
    void ServiceHelper(std::shared_ptr<sock::TcpSocket> ts, inetaddr::InetAddr client)
    {
        int fd = ts->GetSockfd();
        LOG(INFO, "client ip: %s, port: %d, fd: %d\n", client.getip().c_str(), client.getport(), fd);

        std::string out;
        while (true)
        {
            int n = ts->Recv(&out);
            // LOG(INFO, "get a message: %s\n", out.c_str());
            if (n <= 0)
                break;

            while (true)
            {
                std::string package = Decode(out);
                if (package == "")
                    break;
                
                // Request req;
                // req.deserialize(package);
                // std::shared_ptr<Response> resp = _exec(std::make_shared<Request>(req._x, req._y, req._op));
                
                std::shared_ptr<Request> req(new Request);
                req->deserialize(package);

                std::shared_ptr<Response> resp = _exec(req);

                req->print();
                resp->print();
            }
        }
    }

private:
    exec_t _exec;
};

// ./server 8080
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usage: " << "\r\n\t" << argv[0] << " [ip] [port]" << std::endl;
        return USAGEERROR;
    }

    uint16_t port = std::stoi(argv[1]);

    // std::cout << "ip: " << ip << ", port: " << port << std::endl;

    Calculate calculate;
    exec_t cal = std::bind(&Calculate::Execute, &calculate, std::placeholders::_1);

    Service serv(cal);
    func_t callback = std::bind(&Service::ServiceHelper, &serv, std::placeholders::_1, std::placeholders::_2);

    std::unique_ptr<TcpServer> uts(new TcpServer(ip, port, callback));
    uts->Start();
    uts->Run();

    return 0;
}